package com.zeng.excel.controller;

import cn.hutool.core.lang.Pair;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zeng.excel.mapper.UserBaseMapper;
import com.zeng.excel.model.UserBase;
import com.zeng.excel.response.RespBean;
import com.zeng.excel.service.EasyExcelServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@RestController
@RequestMapping("/employee/excel")
@AllArgsConstructor
@Slf4j
public class EasyExcellController {

    @Autowired
    EasyExcelServiceImpl easyExcel;

    /**
     * 导入百万excel文件
     * @param file
     * @return
     */
    @RequestMapping("/import")
    public RespBean easyExcelImport(MultipartFile file){
        if(file.isEmpty()){
            return RespBean.error("文件不可为空");
        }
        easyExcel.easyExcelImport(file);
        return RespBean.ok("文件导入成功");
    }

    /**
     * 下载用户信息模板
     * @param response
     */
    @RequestMapping("/exporttemplate")
    public void downloadTemplate(HttpServletResponse response){
        try {
            //设置文件名
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/用户信息模板.xlsx");
            //设置头文件,注意文件名若为中文，使用encode进行处理
            response.setHeader("Content-disposition", "attachment;fileName=" +  java.net.URLEncoder.encode("用户信息模板.xlsx", "UTF-8"));
            //设置文件传输类型与编码
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            OutputStream outputStream = response.getOutputStream();
            byte[] bytes = new byte[2048];
            int len;
            while((len = inputStream.read(bytes)) != -1){
                outputStream.write(bytes,0,len);
            }
            outputStream.flush();
            outputStream.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Resource
    private UserBaseMapper userbaseMapper;

    /**
     * 导出百万excel文件
     * @param response
     */

    public void easyExcelExport(HttpServletResponse response){
        try {
            //设置内容类型
            response.setContentType("text/csv");
            //设置响应编码
            response.setCharacterEncoding("utf-8");
            //设置文件名的编码格式,防止文件名乱码
            String fileName = URLEncoder.encode("用户信息", "UTF-8");
            //固定写法,设置响应头
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
            Integer total = userbaseMapper.countNum();
            if (total == 0) {
                log.info("查询无数据");
                return;
            }
            //指定用哪个class进行写出
            ExcelWriter build = EasyExcel.write(response.getOutputStream(), UserBase.class).build();
            //设置一个sheet页存储所有导出数据
            WriteSheet writeSheet = EasyExcel.writerSheet("sheet").build();
            long pageSize = 10000;
            long pages = total / pageSize;
            long startTime = System.currentTimeMillis();
            //数据量只有一页时直接写出
            if(pages < 1){
                List<UserBase> userBases = userbaseMapper.selectList(null);
                build.write(userBases, writeSheet);
            }
            //大数据量时，进行分页查询写入
            for (int i = 0; i <= pages; i++) {
                Page<UserBase> page = new Page<>();
                page.setCurrent(i + 1);
                page.setSize(pageSize);
                Page<UserBase> userPage = userbaseMapper.selectPage(page, null);
                build.write(userPage.getRecords(), writeSheet);
            }
            build.finish();
            log.info("导出耗时/ms:"+(System.currentTimeMillis()-startTime)+",导出数据总条数："+total);
        } catch (Exception e) {
            log.error("easyExcel导出失败，e:{}",e.getMessage(),e);
        }
    }

    @Autowired
    @Qualifier("customThreadPool")
    private ThreadPoolTaskExecutor executor;

    @RequestMapping("/easyexcelexport")
    public void exportList(HttpServletResponse response) throws IOException {
        try {
            //设置内容类型
            response.setContentType("text/csv");
            //设置响应编码
            response.setCharacterEncoding("utf-8");
            //设置文件名的编码格式,防止文件名乱码
            String fileName = URLEncoder.encode("用户信息", "UTF-8");
            //固定写法,设置响应头
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
            Integer total = userbaseMapper.countNum();
            if (total == 0) {
                log.info("查询无数据");
                return;
            }
            //指定用哪个class进行写出
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), UserBase.class).build();
            //设置一个sheet页存储所有导出数据
            WriteSheet writeSheetAll = EasyExcel.writerSheet("sheet").build();
            long pageSize = 1000;
            long pages = total / pageSize;
            long startTime = System.currentTimeMillis();
            //数据量只有一页时直接写出
            if(pages < 1){
                List<UserBase> userBases = userbaseMapper.selectList(null);
                excelWriter.write(userBases, writeSheetAll);
            }

            List<CompletableFuture> completableFuturesAll = new ArrayList<>();
            for (int i = 0; i < pages + 1; i++) {
                int finalI = i;
                CompletableFuture<Void> completableFuture = CompletableFuture
                        .supplyAsync(() -> {
                            List<UserBase> userBaseList = userbaseMapper.selectPage(
                                            new Page<>(finalI + 1, pageSize), null)
                                    .getRecords();
                            return Pair.of(finalI, userBaseList);
                            }, executor)
                        .thenAcceptAsync(pair -> {

                            int sheetIndex = pair.getKey();
                            List<UserBase> userList = pair.getValue();

                            if (!CollectionUtils.isEmpty(userList)) {
                                synchronized (excelWriter) {
                                    WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, "用户" + (sheetIndex + 1))
                                            .head(UserBase.class)
                                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                                            .build();
                                    excelWriter.write(userList, writeSheet);
                                }
                            }
                        });

                completableFuturesAll.add(completableFuture);
            }

            // 这里不再需要join每个CompletableFuture，因为我们已经确保了在同一个线程中按顺序写入
            // 但是，如果需要确保所有任务完成，可以使用 CompletableFuture.allOf()
            CompletableFuture.allOf(completableFuturesAll.toArray(new CompletableFuture[0])).join();

            excelWriter.finish();
        } catch (Exception e) {
            log.error("easyExcel导出失败，e:{}",e.getMessage(),e);
        }
    }

    // 按sheetIndex顺序导出
    @RequestMapping("/easyexcelexport1")
    public void exportList1(HttpServletResponse response) throws IOException {
        try {
            //设置内容类型
            response.setContentType("text/csv");
            //设置响应编码
            response.setCharacterEncoding("utf-8");
            //设置文件名的编码格式,防止文件名乱码
            String fileName = URLEncoder.encode("用户信息", "UTF-8");
            //固定写法,设置响应头
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
            Integer total = userbaseMapper.countNum();
            if (total == 0) {
                log.info("查询无数据");
                return;
            }
            //指定用哪个class进行写出
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), UserBase.class).build();
            //设置一个sheet页存储所有导出数据
            WriteSheet writeSheetAll = EasyExcel.writerSheet("sheet").build();
            long pageSize = 1000;
            long pages = total / pageSize;
            long startTime = System.currentTimeMillis();
            //数据量只有一页时直接写出
            if(pages < 1){
                List<UserBase> userBases = userbaseMapper.selectList(null);
                excelWriter.write(userBases, writeSheetAll);
            }

            List<Pair<Integer, List<UserBase>>> dataList = new ArrayList<>();
            //Executor executor1 = Executors.newFixedThreadPool(4); // 或者使用你自定义的线程池

            for (int i = 0; i <= pages; i++) {
                int finalI = i;
                CompletableFuture<Pair<Integer, List<UserBase>>> completableFuture = CompletableFuture.supplyAsync(
                        () -> Pair.of(finalI, userbaseMapper.selectPage(
                                new Page<>(finalI + 1, pageSize), null).getRecords()),
                        executor);
                dataList.add(completableFuture.join()); // 直接加入结果，避免异步写入的顺序问题
            }

            // 按顺序写入
            for (Pair<Integer, List<UserBase>> pair : dataList) {
                int sheetIndex = pair.getKey();
                List<UserBase> userList = pair.getValue();
                if (!CollectionUtils.isEmpty(userList)) {
                    WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, "用户" + (sheetIndex + 1))
                            .head(UserBase.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                            .build();
                    synchronized (excelWriter) { // 确保写入操作的原子性
                        excelWriter.write(userList, writeSheet);
                    }
                }
            }

            excelWriter.finish();
        } catch (Exception e) {
            log.error("easyExcel导出失败，e:{}",e.getMessage(),e);
        }
    }

    /**
     * 获取线程池配置信息
     *
     * @return 一个map，封装线程池信息
     */
    @GetMapping("/getThreadPoolInfo")
    public Map<String,Object> getThreadPoolInfo() {
        HashMap<String, Object> threadPoolInfo = new HashMap<>();

        threadPoolInfo.put("核心线程数", executor.getCorePoolSize());
        threadPoolInfo.put("最大线程数", executor.getMaxPoolSize());
        threadPoolInfo.put("当前线程总数", executor.getPoolSize());
        threadPoolInfo.put("工作时线程数", executor.getActiveCount());
        threadPoolInfo.put("非核心线程存活时间", executor.getKeepAliveSeconds());

        return threadPoolInfo;
    }

}
